import json
from datetime import datetime
from typing import TYPE_CHECKING, Any, Union, Dict, Self, Optional, List

from passlib.context import CryptContext
from pydantic import model_validator, BaseModel
from sqlmodel import Field, Relationship
from sqlmodel import SQLModel

from .base import SQLBaseModel, IdType
from .user_role import UserRole
from ..config import settings
from ..schemas.base_schema import GenderEnum

if TYPE_CHECKING:
    from .role import Role
    from .device import Device

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

class BaseUser(SQLModel):

    username: str = Field(index=True, description="用户名")

    name: Optional[str] = Field(default=None, description="真实姓名")

    nickname: Optional[str] = Field(default=None, description="昵称")
    gender: Optional[GenderEnum] = Field(default=None, description="性别")
    address: Optional[str] = Field(default=None, description="地址")
    age: Optional[int] = Field(default=None, description="年龄")

    avatar: Optional[str] = Field(default=None, description="头像")
    phone_number: Optional[str] = Field(default=None, index=True, description="手机号")
    email: Optional[str] = Field(default=None, index=True, description="邮箱")
    description: Optional[str]  = Field(default=None, description="描述")

    is_super_admin: bool = Field(default=False, description="超级管理员")
    is_enabled: bool = Field(default=True, index=True, description="启用")



class User(SQLBaseModel, BaseUser, table=True):
    __tablename__ = "user"

    hashed_password: str = Field( nullable=False, index=True, description="哈希密码")

    password_changed_datetime: Optional[datetime] = Field(default=None,description="最后一次修改密码时间")

    last_login_datetime: Optional[datetime]  = Field(default=None, description="最后登录时间")

    """多对多关系"""
    roles: List["Role"] = Relationship(back_populates="users", link_model=UserRole)

    """一对多关系"""
    devices: List["Device"] = Relationship(back_populates="user")

    @staticmethod
    def get_password_hash(plain_password: str) -> str:
        """生成密码哈希（自动处理盐值）"""
        return pwd_context.hash(plain_password)

    @staticmethod
    def verify_password(plain_password:str,hashed_password:str) -> bool:
        """验证密码"""
        return pwd_context.verify(plain_password, hashed_password)

    @model_validator(mode='before')
    @classmethod
    def model_convert(cls, data:Any)->Any:
        """预处理输入数据"""
        result = {}

        # 密码处理
        if hasattr(data, "password"):
            password = getattr(data, "password") or settings.DEFAULT_PASSWORD
            result["hashed_password"] = cls.get_password_hash(plain_password=password)

        # 地址处理
        if hasattr(data, "address") and isinstance(getattr(data,"address"), list):
            result["address"] = json.dumps(getattr(data,"address"), ensure_ascii=False)

        return {**data.__dict__, **result}

    def sqlmodel_update(
        self,
        obj: Union[Dict[str, Any], BaseModel],
        *,
        update: Union[Dict[str, Any], None] = None,
    ) -> Self:
        """增强更新方法的安全处理"""
        update_dict = obj.model_dump() if isinstance(obj, BaseModel) else obj

        # 密码更新特殊处理
        if "password" in update_dict:
            update_dict ["hashed_password"] = self.get_password_hash(update_dict["password"])
            update_dict["password_changed_datetime"] = datetime.now()
            del update_dict["password"]  # 移除明文密码

        # 地址处理
        if 'address' in update_dict  and isinstance(update_dict ['address'], list):
            update_dict ['address'] = json.dumps(update_dict ['address'], ensure_ascii=False)

        super().sqlmodel_update(update_dict, update=update)
        return self

